package com.songyuesheng.app.util;

import cn.hutool.core.util.StrUtil;
import com.songyuesheng.app.commom.ContextHolder;
import com.songyuesheng.app.entity.User;
import com.songyuesheng.app.mapper.UserMapper;
import io.jsonwebtoken.ExpiredJwtException;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

@Component
public class JwtUtil {

    private static UserMapper staticUserMapper;

    @Resource
    UserMapper userMapper;

    @PostConstruct
    public void setUserService() {
        staticUserMapper = userMapper;
    }

    /**
     * 令牌密码 不少于32位
     */
    private static final String SECRET = "token_secret";

    /**
     * 令牌前缀
     */
    public static final String TOKEN_PREFIX = "Bearer";

    /**
     * 访问令牌过期时间(1小时)
     */
    private static final Integer ACCESS_TOKEN_EXPIRE_SECONDS = 60 * 60;

    /**
     * 刷新令牌过期时间(7天)
     */
    private static final Integer REFRESH_TOKEN_EXPIRE_SECONDS = 60 * 60 * 24 * 7;

    /**
     * 创建Jwt密钥,加密解密都需要
     */
    public static final SecretKey key = Jwts.SIG.HS256.key()
            .random(new SecureRandom(SECRET.getBytes(StandardCharsets.UTF_8)))
            .build();

    /**
     * 生成访问令牌
     */
    public static String generateAccessToken(String username, Map<String, Object> map) {
        Date now = new Date();
        long expireTime = now.getTime() + ACCESS_TOKEN_EXPIRE_SECONDS * 1000L;
        JwtBuilder jwt = Jwts.builder()
                .id("song")
                .issuer("Vincent")
                .claims(map)
                .subject(username)
                .issuedAt(now)
                .expiration(new Date(expireTime))
                .signWith(key);
        return TOKEN_PREFIX + "_" + jwt.compact();
    }

    /**
     * 生成刷新令牌
     */
    public static String generateRefreshToken(String username, Map<String, Object> map) {
        Date now = new Date();
        long expireTime = now.getTime() + REFRESH_TOKEN_EXPIRE_SECONDS * 1000L;
        JwtBuilder jwt = Jwts.builder()
                .id("song")
                .issuer("Vincent")
                .claims(map)
                .subject(username)
                .issuedAt(now)
                .expiration(new Date(expireTime))
                .signWith(key);
        return TOKEN_PREFIX + "_REFRESH_" + jwt.compact();
    }

    /**
     * 验证访问令牌
     */
    public static Map<String, Object> resolveAccessToken(String token) {
        if (token == null) {
            throw new RuntimeException("token为空");
        }
        try {
            String actualToken = token.replaceFirst(TOKEN_PREFIX + "_", "");
            Map<String, Object> payload = Jwts.parser()
                    .verifyWith(key)
                    .build()
                    .parseSignedClaims(actualToken)
                    .getPayload();
            return payload;
        } catch (ExpiredJwtException e) {
            throw new RuntimeException("访问令牌已过期");
        } catch (Exception e) {
            System.err.println("Token解析异常: " + e.getMessage());
            throw new RuntimeException("访问令牌解析异常: " + e.getMessage());
        }
    }

    /**
     * 验证刷新令牌
     */
    public static Map<String, Object> resolveRefreshToken(String token) {
        if (token == null) {
            throw new RuntimeException("刷新令牌为空");
        }
        try {
            return Jwts.parser()
                    .verifyWith(key)
                    .build()
                    .parseSignedClaims(token.replaceFirst(TOKEN_PREFIX + "_REFRESH_", ""))
                    .getPayload();
        } catch (ExpiredJwtException e) {
            throw new RuntimeException("刷新令牌已过期");
        } catch (Exception e) {
            throw new RuntimeException("刷新令牌解析异常");
        }
    }

    /**
     * 获取当前登录的用户信息
     */
    public static User getCurrentUser() {
        try {
            HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
            String token = request.getHeader("Authorization");
            if (StrUtil.isNotBlank(token)) {
                Long userId = ContextHolder.getUserId();
                if (userId != null) {
                    return staticUserMapper.selectById(userId);
                }
            }
        } catch (Exception e) {
            return null;
        }
        return null;
    }
}
